import { rollback } from '../src/rollback';
import { IParams } from '../src/params';
import { SaeInterface } from '../src/sae';
import * as sinon from 'sinon';
import { expect } from 'chai';
import * as step from '@flow-step/step-toolkit'
import {
    AbortChangeOrderRequest,
    AbortChangeOrderResponse,
} from '@alicloud/sae20190506'


const params: IParams = {
    PACKAGE: '',
    APPLICATION_ID: 'app123',
    Batch: '',
    BatchWaitTime: '',
    ReleaseType: '',
    StrategyType: '',
    USE_ACR_EE: false,
    buildJobID: 0,
    domestic: false,
    minReadyInstanceType: '',
    pipelineID: 0,
    pipelineName: '',
    projectDir: '',
    regionID: 'cn-hangzhou',
    workSpace: '',
    CHANGE_ORDER_ID: '12345',
    APP_NAME: 'my-app'
};


describe('rollback', () => {
    let mockSae: SaeInterface;
    let sandbox: sinon.SinonSandbox;
    let abortAndRollbackChangeOrderStub: sinon.SinonStub;
    let abortChangeOrderStub: sinon.SinonStub;
    let addOutputStub: sinon.SinonStub;
    let addLinkStub: sinon.SinonStub;


    beforeEach(() => {
        sandbox = sinon.createSandbox();
        abortAndRollbackChangeOrderStub = sandbox.stub();
        abortChangeOrderStub = sandbox.stub();
        addOutputStub = sandbox.stub(step, 'addOutput').resolves();
        addLinkStub = sandbox.stub(step.interaction, 'addLink').resolves();

        mockSae = {
            abortChangeOrder: abortChangeOrderStub
        } as unknown as SaeInterface;

    });

    afterEach(() => {
        sandbox.restore();
    });

    it('should successfully rollback deployment', async () => {
        const mockResponse = new AbortChangeOrderResponse({
            body: {
                code: '200',
                message: 'success'
            }
        });

        abortChangeOrderStub.resolves(mockResponse);

        try {
            await rollback(params, mockSae);
            expect.fail('Expected rollback to throw an error');
        } catch (error: any) {
            expect(error.message).to.equal('CURRENT DEPLOYMENT IS CANCELLED MANUALLY');
            expect(abortChangeOrderStub.calledOnce).to.be.true;
            expect(abortChangeOrderStub.firstCall.args[0]).to.deep.equal(new AbortChangeOrderRequest({ changeOrderId: '12345' }));
            expect(addOutputStub.calledWith('CHANGE_ORDER_ID=12345')).to.be.true;
            expect(addOutputStub.calledWith('APP_NAME=my-app')).to.be.true;
            expect(addLinkStub.calledWith('Change Order Details','https://saenext.console.aliyun.com/cn-hangzhou/app-list/app123/micro-app/record/12345',41)).to.be.true;

        }
    });

    it('should throw an error if CHANGE_ORDER_ID is not set', async () => {
        const paramsWithoutChangeOrderId: IParams = { ...params, CHANGE_ORDER_ID: undefined };

        try {
            await rollback(paramsWithoutChangeOrderId, mockSae);
            expect.fail('Expected rollback to throw an error');
        } catch (error: any) {
            expect(error.message).to.equal('CHANGE_ORDER_ID is not set in environment variables');
        }
    });

    it('should throw an error if abortChangeOrder fails', async () => {
        const error = new Error('Some error occurred');
        abortChangeOrderStub.rejects(error);

        try {
            await rollback(params, mockSae);
            expect.fail('Expected rollback to throw an error');
        } catch (e: any) {
            expect(e.message).to.equal(`failed to abortChangeOrder: ${error}`);
        }
    });

    it('should throw an error if the response code is not 200', async () => {
        const mockResponse = new AbortChangeOrderResponse({
            body: {
                code: '500',
                message: 'Service Error'
            }
        });

        abortChangeOrderStub.resolves(mockResponse);

        try {
            await rollback(params, mockSae);
            expect.fail('Expected rollback to throw an error');
        } catch (e: any) {
            expect(e.message).to.equal(`rollback deployment failed, code: ${mockResponse.body?.code}, message: ${mockResponse.body?.message}`);
        }
    });

});
